package com.swak.boot.config.job;

import java.util.List;

import javax.sql.DataSource;

import org.h2.Driver;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.swak.boot.config.customizer.SyncDataSourceOptionsCustomizer;
import com.swak.boot.config.jdbc.database.DataSourceProperties;
import com.swak.closable.ShutDownHook;
import com.swak.job.storage.StorageService;
import com.swak.job.storage.h2.StorageServiceForH2;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;

/**
 * H2StorageAutoConfiguration.
 * 
 * @author DELL
 */
@Configuration
@ConditionalOnClass({ DataSource.class, Driver.class })
@ConditionalOnMissingBean(StorageService.class)
@ConditionalOnProperty(prefix = "spring.job.db", name = "enable", matchIfMissing = true)
public class H2StorageAutoConfiguration {

	/**
	 * 构建 HikariDataSource
	 * 
	 * @return
	 */
	@Bean
	public StorageService jobStorageService(JobProperties properties,
			ObjectProvider<List<SyncDataSourceOptionsCustomizer>> customizersProvider) {
		DataSource dataSource = this.createDataSource(properties.getDb(), customizersProvider);
		return new StorageServiceForH2(dataSource, properties.getModule());
	}

	private DataSource createDataSource(DataSourceProperties properties,
			ObjectProvider<List<SyncDataSourceOptionsCustomizer>> customizersProvider) {
		HikariConfig config = new HikariConfig();
		config.setPoolName("Job-DB");
		config.setJdbcUrl(properties.getUrl());
		config.setUsername(properties.getUsername());
		config.setPassword(properties.getPassword());
		config.setDriverClassName(properties.getDriverClassName());

		config.addDataSourceProperty("cachePrepStmts", "true");
		config.addDataSourceProperty("prepStmtCacheSize", properties.getPrepStmtCacheSize());
		config.addDataSourceProperty("prepStmtCacheSqlLimit", properties.getPrepStmtCacheSqlLimit());
		config.addDataSourceProperty("useServerPrepStmts", "true");
		config.addDataSourceProperty("useLocalSessionState", "true");
		config.addDataSourceProperty("rewriteBatchedStatements", "true");
		config.addDataSourceProperty("cacheResultSetMetadata", "true");
		config.addDataSourceProperty("cacheServerConfiguration", "true");
		config.addDataSourceProperty("elideSetAutoCommits", "true");
		config.addDataSourceProperty("maintainTimeStats", "false");
		config.setMinimumIdle(properties.getMinIdle()); // 最小空闲连接数量
		config.setIdleTimeout(properties.getMinEvictableIdleTimeMillis()); // 空闲连接存活最大时间，默认600000（10分钟）
		config.setMaximumPoolSize(properties.getMaxActive()); // 连接池最大连接数，默认是10
		config.setConnectionTimeout(properties.getMaxWait()); // 数据库连接超时时间,默认30秒，即30000
		config.setMaxLifetime(properties.getMaxLifetime()); // 连接的最长生命周期，值0表示无限生命周期，默认1800000即30分钟

		// 创建连接
		HikariDataSource dataSource = new HikariDataSource(config);

		List<SyncDataSourceOptionsCustomizer> customizers = customizersProvider != null
				? customizersProvider.getIfAvailable()
				: null;
		if (customizers != null && !customizers.isEmpty()) {
			for (SyncDataSourceOptionsCustomizer customizer : customizers) {
				customizer.customize(dataSource);
			}
		}

		// 注册关闭
		ShutDownHook.registerShutdownHook(() -> {
			dataSource.close();
		});
		return dataSource;
	}
}
